// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Data/CommonEnum.h"
#include "Data/SaveInfoStruct.h"
#include "InputCoreTypes.h"
#include "MissionComponent.generated.h"

class APlayerCameraManager;
class USpringArmComponent;
class USingleMarkerWidget;
class ALandmarkMaster;
class UCompassWidget;
class UInMissionWidget;
class UOnMissionFinishedWidget;
class UTimerWidget;
class UInteractionWidget;
class UGlobalNotificationWidget;
class ULocationObjectivesWidget;
class USaveGameWidget;
class UPlayerLevelWidget;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class MISCELLANEOUSPROJECT_API UMissionComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UMissionComponent();

protected:
	virtual void BeginPlay() override;

public:
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	virtual void PostInitProperties() override;
	
#if WITH_EDITOR
	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent);
#endif

public:
	void OnCountDownTimerFinished();
public:
	void UnTrackMission();
	void TrackMission(FMissionMaster MissionToStart);
	//=============Event==================
	UFUNCTION(BlueprintImplementableEvent)
	void StopFollowTarget();
	UFUNCTION(BlueprintImplementableEvent)
	void StartFollowTarget();

	void BuildMissionComponent();
	void Interaction_With_NPC();
	void UpdateNewGame(bool InIsNewGame) { IsNewGame = InIsNewGame; }
	//=======Macros=================
	bool IsLocallyControlled(APawn*& ControlledPawn);
	bool IsInMisssion();
	bool IsOnScreen(FVector WorldLocation, FVector ExtraPading, bool HidOnScreenEdge);
	//========Main================
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void GetOwnerCamera(APlayerCameraManager*& OutCameraManager, USpringArmComponent*& OutSpringArm, FTransform& OutCameraTransform);
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void SetCompassReference();
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void PopulateDirections();
	void ToggleOwnerInput(const bool& Enabled);

	//==========Calculations===========
	float RotateCircleToDegree(float In);
	void RotationToTranslation(const FRotator& RotatorA, const FRotator& RotatorB, FVector2D& OutTranslation, bool& Clockwise, bool& InRadarSight);
	float GetDeltaClockwise(const float& A, const float& b, bool ClockWise);
	int32 CalculateDistance(const FVector& LocationA, const FVector& LocationB);
	EElevationState CalculateElevation(const float& Z);
	void MarkerWorldLocationToScreen(const FVector& WorldLocation, const FVector& ExtraPadding, USingleMarkerWidget* MarkerReference, FVector2D& OutScreenPosition, bool& OutOnScreen, float& OutDegree, bool& OutOnEdge);

	//==============Markers==============
	//===========Update Markers==========
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void UpdateCompassDirections();
	void UpdateCompassMarker(USingleMarkerWidget* WidgetReference, AActor* TargetActor, FVector LastKnownLocation);
	void UpdateMarkers(EMarkerType MarkerType);
	void UpdateMarkerDistance(USingleMarkerWidget* MarkerReference, AActor* TargetActor, FVector NearestLocation);
	void UpdateScreenMarker(USingleMarkerWidget* MarkerReference, AActor* TargetActor, FVector NearestLocation, FVector ExtraPadding);
	void UpdateInteractionWidgetPosition();

	void UpdateMarkerTargetInfo();
	void AddObjectiveMarkers();
	void RemoveObjectiveMarker(const FTargetInfo& InTargetInfo);
	void RemoveFromRealMarkers(const USingleMarkerWidget* MarkerReference, bool Animate);
	void ClearAllObjectiveMarkers();
	void ToggleWidgets(EToggleVisibility Visibility);
	void RemoveFromCustomMarkers(const FTargetInfo& InTargetInfo);

	//=============Custom=====================
	bool FollowTarget();
	void OnCustomObjectiveTypes();
	//==============Objectives================
	void PopulateObjectives();
	void UpdateObjectiveProgress(const FTargetInfo& InTargetInfo);

	//==========Pure Functions===============
	bool CanSkipToNextSequence();
	bool ObjectivesAreDone();
	bool DistanceWithFollowingTarget(float InDistance);
	void ContainsInKnownNPCs(const FTargetInfo& InTargetInfo, FDefaultNPCInfo& OutValue, bool& OutContains);;
	bool IsNearestActorEnabled();
	bool ContainsInActorsToInteract(const FTargetInfo& InTargetInfo);

	FObjectives FindSpecialObjective(EObjectiveType SpecialObjective);
	void FindInDefaultActors(const FDefaultNPCInfo& InActorInfo, FDefaultNPCInfo& OutValue, int32& OutIndex);
	USingleMarkerWidget* FindDefaultMarkers(FName InUniqueName);
	void FindInOverlappedNPCs(const FTargetInfo& InTargetInfo, bool& OutFounded, FTargetInfo& OutValue);
	FTargetInfo FindNearestOverlappedNPC();

	//========Camera Events===================
	void TriggerCamera();
	void SetCameraDefaults();
	void GetCameraDefaults(float& OutDefaultArmLength, FVector& OutDefaultSocketOffset);

	//===========Widget========================
	void CreateInMissionWidget();
	void CreateInteractionWidget();
	void CreateGlobalNotificationWidget(const float& InDisplayTime, const FText& InHeadline, const FText& InTopText, const bool& InSpecialArea, const FText& InSpecialAreaText, const bool& InGiveXP, const int32& InXPValue, const FLinearColor& InSpecialAreaColor, const FLinearColor& InHeadlineColor, const FLinearColor& InXPTextColor);
	void CreateTimerWidget(const FTimerInfo& TimeInfo);
	void CreateLocationObjectiveWidget(const FLocationObjectiveMaster& InLocationObjective);
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void CreateSaveGameWidget();
	void CreateLevelWidget();

	//===========Interaction================
	void RemoveFromOverlappedNPCs(const FTargetInfo& InTargetInfo);
	void AddToOverlappedNPCs(const FTargetInfo& InTargetInfo);
	void UpdateCustomDepth(const FTargetInfo& InTargetInfo, const bool& InbValue);

	//===========Quest Log==================
	void AddToQuestLog(const FMissionMaster& InMissionInfo);
	void RemoveFromQuestLog(const FMissionMaster& InMissionInfo);
	void SetCompletedOnQuestLog(const FMissionMaster& InMissionInfo);

	//===========Landmarks=============
	void AddLandmark(ALandmarkMaster* InLandmark);
	void RemoveLandmark(const ALandmarkMaster* InLandmark);
	int32 FindLandmarkIndex(const ALandmarkMaster* InLandmark);
	void UpdateLandmarkMarkers();

	//=========Special Area===========
	void OnEnterToSpecialArea(const EToggleVisibility& InHighlightVisibility, const EToggleVisibility& InTextVisibility, const FLinearColor& InBrushColor, const FText& InText);
	void OnExitFromSpecialArea();

	//=======Save Game=================
	void LoadSavedGameForComponent();
	UFUNCTION(BlueprintCallable, Category = MissionComponent)
	void SaveGameOnComponent(bool DisplaySaveWidget);

	void StartMissionFromDataTable(const FDataTableRowHandle& InMissionToStart);
	void StartCustomMission(const FMissionMaster& InMissionToStart);
	bool RestartMission();
private:
	float Modulo(float A, float B);
public:
	//=============Must====================
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<class USingleMarkerWidget> MarkerWidgetClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<class USingleDirectionWidget> DirectionWidgetClass;
	UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=A_Must)
	TSubclassOf<UCompassWidget> CompassClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UInMissionWidget> InMissionClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UOnMissionFinishedWidget> MissionFinishedClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UTimerWidget> TimerClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UInteractionWidget> InteractionClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UGlobalNotificationWidget> GlobalNotificationClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<ULocationObjectivesWidget> LocationObjectiveClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<USaveGameWidget> SaveGameClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TSubclassOf<UPlayerLevelWidget> PlayerLevelClass;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	FDataTableRowHandle StartupMission;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TArray<FDefaultNPCInfo> DefaultActors;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	FTargetInfo NearestOverlappedNPC;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	FMissionMaster CurrentMission;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	FSavedPlayerLevel PlayerLevel;
	//==========Camera Variables=================
	FVector CTargetSocketOffset;
	FRotator CTargetRotation;
	float CTargetArmLength;
	float CInterpSpeed;
	FTimerHandle CCameraTimer;
	bool CEnableInput;
	FRotator CTempCameraRot;
	float DefaultArmLength;
	FVector DefaultSocketOffset;

	//===========Booleans============
	bool Initialized;
	bool InMission;
	bool IsFollowingATarget;
	bool IsNewGame;

	//================Marker Arrays==========
	TArray<USingleMarkerWidget*> ObjectiveMarkers;
	TArray<USingleMarkerWidget*> DefaultActorMarkers;
	//=======Actor Arrays===============
	TArray<FTargetInfo> CurrentTargets;
	TArray<FDefaultNPCInfo> KnownNPCs;
	TArray<FTargetInfo> OverlappedNPCs;
	TArray<FTargetInfo> ActorsToInteract;
	TArray<ALandmarkMaster*> Landmarks;
	TArray<FName> DiscoveredLocations;
	//==========Mission Arrays===============
	TArray<FObjectives> CurrentObjectives;
	TArray<FMissionMaster> AllMissions;

	//===========Widget References==========
	UCompassWidget* CompassReference;
	UInMissionWidget* InMissionWidget;
	UOnMissionFinishedWidget* MissionFinishedWidget;
	UTimerWidget* TimerWidget;
	UInteractionWidget* InteractionWidget;
	UGlobalNotificationWidget* GlobalNotificationWidget;
	ULocationObjectivesWidget* LocationObjectiveWidget;
	USaveGameWidget* SaveGameWidget;
	UPlayerLevelWidget* PlayerLevelWidget;
	//==========Actor References===========
	AActor* TargetToFollow;


	//=========Current Mission==========
	int32 CurrentSequenceIndex;

	//==========Main Setup==============
	float MaximumCompassTranslation;
	float UnitsPerMeter;
	float ElevationRange;
	float FollowMaxDistance;
	float ScreenMarkerRadius;
	float ScreenMarkerMargin;
	//========Interaction================
	TMap<ETargetType, FText> InteractionText;
	FKey InteractionKey;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = A_Must)
	TArray<FDirections> Directions;
};
